<?php

namespace App\Http\Controllers;

use App\Http\Utils\Integral\Time;
use App\Http\Utils\Promotion\Order;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use SimpleSoftwareIO\QrCode\Facades\QrCode;

class PromotionController extends Controller
{
    /**
     * @var int
     */
    protected $page_size = 3;

    const PROMOTION_NOT_FOUND_PLAN = "没有该推广计划";
    const PROMOTION_HAS_JOIN_PLAN = "已经加入该推广计划";
    const PROMOTION_HAS_RELATION = "该商户下已有你的推荐关系";
    const PROMOTION_PARENT_NOT_HAS_RELATION = "没有找商户下的上级关系";
    const PROMOTION_PARENT_NOT_HAS_PLAN = "上级没有加入该计划";
    const PROMOTION_HAS_NOT_JOIN_PLAN = "上级(用户)没有加入该推广计划";
    const PROMOTION_HAS_NOT_PLANS = "没有推广计划";
    const PROMOTION_ORDER_ALREADY_FINISH = "该笔订单已经结算完毕";
    const PROMOTION_HAS_NOT_PLANS_DETAILS = "没有分佣详情";
    const PROMOTION_HAS_NOT_TEAM = "没有推广团队";

    /**
     * @param Request $request
     * @return \App\Http\Utils\Response
     */
    public function create(Request $request)
    {
        $this->validate($request, [
            'shop_id'  => 'required|alpha_num',
            'name'     => 'required|string|min:1|max:255',
            'describe' => 'required|string|min:1|max:255',
            'one'      => 'required|numeric|min:0|max:100',
            'two'      => 'required|numeric|min:0|max:100',
        ]);
        $data = $request->only([
            'shop_id',
            'name',
            'describe',
            'one',
            'two',
        ]);
        $data['token'] = sha1(uniqid($request->input('shop_id')));
        $data['create_time'] = Time::current();
        $data['update_time'] = Time::current();
        return $this->json(
            DB::table('promotion_plan')
                ->insertGetId($data)
        );
    }

    /**
     * @param int $id
     * @return \App\Http\Utils\Response
     * @throws \Exception
     */
    public function delete($id)
    {
        $plan = DB::table('promotion_plan')->where(['id' => $id])->first(['id']);
        if (is_null($plan)) {
            throw new \Exception(self::PROMOTION_NOT_FOUND_PLAN, 404);
        }
        DB::table('promotion_plan')->where(['id' => $id,])->delete();
        return $this->json(null);
    }

    /**
     * @param Request $request
     * @param int $id
     * @return \App\Http\Utils\Response
     * @throws \Exception
     */
    public function edit(Request $request, $id)
    {
        $this->validate($request, [
            'name'     => 'string|min:1|max:255',
            'describe' => 'string|min:1|max:255',
            'one'      => 'numeric|min:0|max:100',
            'two'      => 'numeric|min:0|max:100',
        ]);

        $plan = DB::table('promotion_plan')->where(['id' => $id,])->first();
        if (is_null($plan)) {
            throw new \Exception(self::PROMOTION_NOT_FOUND_PLAN, 404);
        }
        $data = $request->only([
            'name',
            'describe',
            'one',
            'two',
        ]);
        $data['update_time'] = Time::current();
        DB::table('promotion_plan')->where(['id' => $id,])->update($data);
        return $this->json($data);
    }

    /**
     * @param int $id
     * @return \App\Http\Utils\Response
     * @throws \Exception
     */
    public function index($id)
    {
        $plan = DB::table('promotion_plan')->where(['id' => $id,])->first();
        if (is_null($plan)) {
            throw new \Exception(self::PROMOTION_NOT_FOUND_PLAN, 404);
        }
        return $this->json($plan);
    }

    /**
     * @param Request $request
     * @param string $shop_id
     * @param int $page
     * @return \App\Http\Utils\Response
     * @throws \Exception
     */
    public function lists(Request $request, $shop_id, $page)
    {
        $this->validate($request, [
            'page_size' => 'integer|min:1',
        ]);
        $base = DB::table('promotion_plan')->where(['shop_id' => $shop_id]);
        $page_size = $request->input('page_size', $this->page_size);
        $count = $base->count('id');
        $totalPage = ceil($count / $page_size);
        if ($totalPage == 0) {
            throw new \Exception(self::PROMOTION_NOT_FOUND_PLAN, 404);
        }
        $page = ($page <= 1) ? 1 : $page;
        $plan = $base->orderBy('id', 'desc')->offset(($page - 1) * $page_size)->limit($page_size)->get();
        return $this->json([
            'page_size'    => (int)$page_size,
            'count'        => (int)$count,
            'total_page'   => (int)$totalPage,
            'current_page' => (int)$page,
            'plan'         => $plan,
        ]);
    }

    /**
     * @param string $plan_token
     * @return \App\Http\Utils\Response
     * @throws \Exception
     */
    public function planToken($plan_token)
    {
        $plan = DB::table('promotion_plan')
            ->select('promotion_plan.*')
            ->where(['promotion_plan.token' => $plan_token,])
            ->addSelect(DB::raw('shop_info.name as shop_name, shop_info.logo as shop_logo'))
            ->leftJoin(sprintf('%sshop_info as shop_info', env('DB_DATABASE_USER', '')), function ($join) {
                $join->on('shop_info.id', '=', 'promotion_plan.shop_id');
            })->first();
        if (is_null($plan)) {
            throw new \Exception(self::PROMOTION_NOT_FOUND_PLAN, 404);
        }
        return $this->json($plan);
    }

    /*----------------------------------------------------------------------*/

    /**
     * @param Request $request
     * @param string $shop_id
     * @param int $page
     * @return \App\Http\Utils\Response
     * @throws \Exception
     */
    public function shopTeam(Request $request, $shop_id, $page)
    {
        $this->validate($request, [
            'search'    => 'string|max:100',
            'plan_name' => 'string|max:100',
            'page_size' => 'integer|min:1',
        ]);
        $start = $request->input('start', null);
        $end = $request->input('end', null);
        $search = $request->input('search', null);
        $planName = $request->input('plan_name', null);
        $base = DB::table('promotion_join_plan')
            ->select([
                'promotion_join_plan.id',
                'promotion_join_plan.user_id',
                'promotion_join_plan.shop_id',
                'promotion_join_plan.plan_id',
                'promotion_join_plan.commission',
                'promotion_join_plan.update_time',
            ])
            ->where('promotion_join_plan.shop_id', $shop_id)
            ->addSelect([
                'promotion_plan.name',
            ])->leftJoin('promotion_plan', function ($join) {
                $join->on('promotion_plan.id', '=', 'promotion_join_plan.plan_id');
            })

            ->addSelect([
                'user_info.nickname', 'user_info.avatar'
            ])->leftJoin(sprintf('%suser_info as user_info', env('DB_DATABASE_USER', '')), function ($join) {
                $join->on('user_info.user_id', '=', 'promotion_join_plan.user_id');
            })
            ->addSelect([
                'users.mobile',
            ])->leftJoin(sprintf('%suser as users', env('DB_DATABASE_USER', '')), function ($join) {
                $join->on('users.id', '=', 'promotion_join_plan.user_id');
            })
            ->addSelect([
                'promotion_relation.parent_user_id',
            ])->leftJoin('promotion_relation', function ($join) {
                $join->on('promotion_relation.user_id', '=', 'promotion_join_plan.user_id')
                    ->on('promotion_relation.shop_id', '=', 'promotion_join_plan.shop_id');
            })
            ->addSelect([
                'parent_user_info.nickname as parent_nickname',
            ])->leftJoin(sprintf('%suser_info as parent_user_info', env('DB_DATABASE_USER', '')), function ($join) {
                $join->on('parent_user_info.user_id', '=', 'promotion_relation.parent_user_id');
            })->when($start, function ($query) use ($start) {
                $query->where('promotion_join_plan.update_time', '>=', $start);
            })->when($end, function ($query) use ($end) {
                $query->where('promotion_join_plan.update_time', '<=', $end);
            })->when($search, function ($query) use ($search) {
                $query->whereRaw('parent_user_info.nickname LIKE ?', "%{$search}%");
            })->when($planName, function ($query) use ($planName) {
                $query->whereRaw('promotion_plan.name LIKE ?', "%{$planName}%");
            });
        $page_size = $request->input('page_size', $this->page_size);
        $count = $base->count('promotion_join_plan.id');
        $totalPage = ceil($count / $page_size);
        if ($totalPage == 0) {
            throw new \Exception(self::PROMOTION_HAS_NOT_TEAM, 404);
        }
        $page = ($page <= 1) ? 1 : $page;
        $team = $base->orderBy('promotion_join_plan.id', 'desc')->offset(($page - 1) * $page_size)->limit($page_size)->get()
            ->map(function ($value) {
                $value->team_user_count = DB::table('promotion_relation')
                    ->where('promotion_relation.parent_user_id', $value->user_id)
                    ->where('promotion_relation.shop_id', $value->shop_id)
                    ->count();
                return $value;
            });
        return $this->json([
            'page_size'    => (int)$page_size,
            'count'        => (int)$count,
            'total_page'   => (int)$totalPage,
            'current_page' => (int)$page,
            'team'         => $team,
        ]);
    }

    /**
     * @param Request $request
     * @param string $shop_id
     * @param string $user_id
     * @param int $plan_id
     * @param int $page
     * @return \App\Http\Utils\Response
     * @throws \Exception
     */
    public function shopDetails(Request $request, $shop_id, $user_id, $plan_id, $page)
    {
        $this->validate($request, [
            'search'    => 'string|max:100',
            'plan_name' => 'string|max:100',
            'page_size' => 'integer|min:1',
        ]);
        $start = $request->input('start', null);
        $end = $request->input('end', null);
        $search = $request->input('search', null);

        $base = DB::table('promotion_user_flow')
            ->select([
                'promotion_user_flow.id',
                'promotion_user_flow.user_id',
                'promotion_user_flow.shop_id',
                'promotion_user_flow.order_num',
                'promotion_user_flow.info',
                'promotion_user_flow.amount',
                'promotion_user_flow.history',
                'promotion_user_flow.plan_id',
                'promotion_user_flow.create_time',
            ])->where('promotion_user_flow.shop_id', $shop_id)
            ->where('promotion_user_flow.user_id', $user_id)
            ->where('promotion_user_flow.plan_id', $plan_id)
            ->addSelect([
                'promotion_order.total'
            ])->leftJoin('promotion_order', function ($join) {
                $join->on('promotion_order.order_num', '=', 'promotion_user_flow.order_num');
            })
            ->addSelect([
                'user_info.nickname', 'user_info.avatar'
            ])->leftJoin(sprintf('%suser_info as user_info', env('DB_DATABASE_USER', '')), function ($join) {
                $join->on('user_info.user_id', '=', 'promotion_order.user_id');
            })
            ->when($start, function ($query) use ($start) {
                $query->where('promotion_user_flow.create_time', '>=', $start);
            })->when($end, function ($query) use ($end) {
                $query->where('promotion_user_flow.create_time', '<=', $end);
            })->when($search, function ($query) use ($search) {
                $query->whereRaw('promotion_user_flow.order_num LIKE ?', "%{$search}%");
            });
        $page_size = $request->input('page_size', $this->page_size);
        $count = $base->count('promotion_user_flow.id');
        $totalPage = ceil($count / $page_size);
        if ($totalPage == 0) {
            throw new \Exception(self::PROMOTION_HAS_NOT_TEAM, 404);
        }
        $page = ($page <= 1) ? 1 : $page;
        $details = $base->orderBy('promotion_user_flow.id', 'desc')->offset(($page - 1) * $page_size)->limit($page_size)->get();
        return $this->json([
            'page_size'    => (int)$page_size,
            'count'        => (int)$count,
            'total_page'   => (int)$totalPage,
            'current_page' => (int)$page,
            'details'      => $details,
        ]);
    }
    /*----------------------------------------------------------------------*/

    /**
     * @param int $id
     * @return mixed
     * @throws \Exception
     */
    public function qrCode($id)
    {
        return QrCode::encoding('UTF-8')->size(500)->generate(sprintf("token=%s", $id));
    }
    /*----------------------------------------------------------------------*/

    /**
     * @param int $user_id
     * @param string $plan_token
     * @return \App\Http\Utils\Response
     * @throws \Exception
     */
    public function statusPlan($user_id, $plan_token)
    {
        $plan = DB::table("promotion_plan")
            ->where('token', $plan_token)
            ->first();
        if (is_null($plan)) {
            throw new \Exception(self::PROMOTION_NOT_FOUND_PLAN, 404);
        }
        $isJoin = DB::table('promotion_join_plan')
            ->where([
                'user_id' => $user_id,
                'shop_id' => $plan->shop_id,
                'plan_id' => $plan->id,
                'exit'    => 'false',
            ])->first();
        return $this->json(!is_null($isJoin));
    }

    /**
     * @param Request $request
     * @return \App\Http\Utils\Response
     * @throws \Exception
     */
    public function buildRelation(Request $request)
    {
        $this->validate($request, [
            'parent_user_id' => 'required|alpha_num',
            'user_id'        => 'required|alpha_num',
            'plan_token'     => 'required|alpha_num',
        ]);
        $parentUserId = $request->input('parent_user_id');
        $userId = $request->input('user_id');
        $planToken = $request->input('plan_token');
        $plan = DB::table("promotion_plan")
            ->where('token', $planToken)
            ->first();
        if (is_null($plan)) {
            throw new \Exception(self::PROMOTION_NOT_FOUND_PLAN, 202);
        }
        $relation = DB::table('promotion_relation')
            ->where([
                'user_id' => $userId,
                'shop_id' => $plan->shop_id,
            ])->first();
        if (!is_null($relation)) {
            throw new \Exception(self::PROMOTION_HAS_RELATION, 202);
        }
        if ($parentUserId > 0) {
            $parentRelation = DB::table('promotion_relation')
                ->where([
                    'user_id' => $parentUserId,
                    'shop_id' => $plan->shop_id,
                ])->first();
            if (is_null($parentRelation)) {
                throw new \Exception(self::PROMOTION_PARENT_NOT_HAS_RELATION, 202);
            }
            $parentJoin = DB::table('promotion_join_plan')
                ->where([
                    'promotion_join_plan.user_id' => $parentUserId,
                    'promotion_join_plan.shop_id' => $plan->shop_id,
                    'promotion_join_plan.plan_id' => $plan->id,
                    'promotion_join_plan.exit'    => 'false',
                ])
                ->first();
            if (is_null($parentJoin)) {
                throw new \Exception(self::PROMOTION_PARENT_NOT_HAS_PLAN, 202);
            }
        } else {
            $parentUserId = 0;
        }
        DB::table('promotion_relation')
            ->insert([
                'user_id'        => $userId,
                'shop_id'        => $plan->shop_id,
                'plan_id'        => $plan->id,
                'parent_user_id' => $parentUserId,
                'create_time'    => Time::current(),
                'update_time'    => Time::current(),
            ]);
        return $this->json(sprintf("建立[%s>>>>>推荐>>>>>%s]关系成功", $parentUserId, $userId));
    }

    /**
     * @param Request $request
     * @return \App\Http\Utils\Response
     * @throws \Exception
     */
    public function joinPlan(Request $request)
    {
        $this->validate($request, [
            'user_id'    => 'required|alpha_num',
            'plan_token' => 'required|alpha_num',
        ]);
        $plan = DB::table("promotion_plan")
            ->where('token', $request->input('plan_token'))
            ->first();
        if (is_null($plan)) {
            throw new \Exception(self::PROMOTION_NOT_FOUND_PLAN, 404);
        }
        $isJoin = DB::table('promotion_join_plan')
            ->where([
                'user_id' => $request->input('user_id'),
                'shop_id' => $plan->shop_id,
                'plan_id' => $plan->id,
            ])->first();
        if (!is_null($isJoin)) {
            if ($isJoin->exit === 'false') {
                throw new \Exception(self::PROMOTION_HAS_JOIN_PLAN, 404);
            } else {
                DB::table('promotion_join_plan')
                    ->where([
                        'user_id' => $request->input('user_id'),
                        'shop_id' => $plan->shop_id,
                        'plan_id' => $plan->id,
                    ])->update([
                        'exit'        => 'false',
                        'update_time' => Time::current(),
                    ]);
                return $this->json('开启推广计划成功');
            }
        } else {
            DB::table('promotion_join_plan')->insert([
                'user_id'     => $request->input('user_id'),
                'shop_id'     => $plan->shop_id,
                'plan_id'     => $plan->id,
                'exit'        => 'false',
                'create_time' => Time::current(),
                'update_time' => Time::current(),
            ]);
            return $this->json('加入推广计划成功');
        }
    }

    /**
     * @param Request $request
     * @return \App\Http\Utils\Response
     * @throws \Exception
     * @throws \Throwable
     */
    public function leavePlan(Request $request)
    {
        $this->validate($request, [
            'user_id'    => 'required|alpha_num',
            'plan_token' => 'required|alpha_num',
        ]);
        $plan = DB::table("promotion_plan")
            ->where('token', $request->input('plan_token'))
            ->first();
        if (is_null($plan)) {
            throw new \Exception(self::PROMOTION_NOT_FOUND_PLAN, 404);
        }
        DB::beginTransaction();
        try {
            DB::table('promotion_join_plan')
                ->where([
                    'user_id' => $request->input('user_id'),
                    'shop_id' => $plan->shop_id,
                    'plan_id' => $plan->id,
                ])->update([
                    'exit'        => 'true',
                    'update_time' => Time::current(),
                ]);
            $oldPlan = DB::table('promotion_relation')
                ->where([
                    'user_id' => $request->input('user_id'),
                    'shop_id' => $plan->shop_id,
                ])->first(['plan_id', 'parent_user_id']);
            if (!is_null($oldPlan)) {
                DB::table('promotion_relation')
                    ->where([
                        'parent_user_id' => $request->input('user_id'),
                        'shop_id'        => $plan->shop_id,
                    ])->update([
                        'plan_id'        => $oldPlan->plan_id,
                        'parent_user_id' => $oldPlan->parent_user_id,
                        'update_time'    => Time::current(),
                    ]);
            }
            DB::commit();
            return $this->json('退出推广计划成功');
        } catch (\Throwable $throwable) {
            DB::rollBack();
            throw $throwable;
        }
    }

    /**
     * @param Request $request
     * @param string $user_id
     * @param int $page
     * @return \App\Http\Utils\Response
     * @throws \Exception
     */
    public function userPlans(Request $request, $user_id, $page)
    {
        $this->validate($request, [
            'search'    => 'string|max:100',
            'page_size' => 'integer|min:1',
            'exit'      => 'in:true,false',
        ]);
        $start = $request->input('start', null);
        $end = $request->input('end', null);
        $exit = $request->input('exit', null);
        $search = $request->input('search', null);
        $base = DB::table('promotion_join_plan')
            ->select([
                'promotion_join_plan.user_id',
                'promotion_join_plan.shop_id',
                'promotion_join_plan.create_time',
                'promotion_join_plan.exit',
                'promotion_plan.name',
                'promotion_plan.describe',
                'promotion_plan.one',
                'promotion_plan.two',
                'promotion_plan.token',
                'promotion_relation.parent_user_id',
            ])->leftJoin('promotion_plan', function ($join) {
                $join->on('promotion_plan.id', '=', 'promotion_join_plan.plan_id');
            })->leftJoin('promotion_relation', function ($join) {
                $join->on('promotion_relation.user_id', '=', 'promotion_join_plan.user_id')
                    ->on('promotion_relation.shop_id', '=', 'promotion_join_plan.shop_id');
            })->addSelect(DB::raw('shop_info.name as shop_name, shop_info.logo as shop_logo'))
            ->leftJoin(sprintf('%sshop_info as shop_info', env('DB_DATABASE_USER', '')), function ($join) {
                $join->on('shop_info.id', '=', 'promotion_relation.shop_id');
            })->addSelect([
                'user_info.nickname', 'user_info.avatar'
            ])->leftJoin(sprintf('%suser_info as user_info', env('DB_DATABASE_USER', '')), function ($join) {
                $join->on('user_info.user_id', '=', 'promotion_relation.user_id');
            })->addSelect([
                'parent_user_info.nickname as parent_nickname', 'parent_user_info.avatar as parent_avatar'
            ])->leftJoin(sprintf('%suser_info as parent_user_info', env('DB_DATABASE_USER', '')), function ($join) {
                $join->on('parent_user_info.user_id', '=', 'promotion_relation.parent_user_id');
            })->when($start, function ($query) use ($start) {
                $query->where('promotion_relation.create_time', '>=', $start);
            })->when($end, function ($query) use ($end) {
                $query->where('promotion_relation.create_time', '<=', $end);
            })->when($search, function ($query) use ($search) {
                $query->whereRaw('shop_info.name LIKE ?', "%{$search}%");
            })->when($exit, function ($query) use ($exit) {
                if ($exit === 'true') {
                    $query->where('promotion_join_plan.exit', 'true');
                } else {
                    $query->where('promotion_join_plan.exit', 'false');
                }
            })->where([
                'promotion_join_plan.user_id' => $user_id,
            ]);
        $page_size = $request->input('page_size', $this->page_size);
        $count = $base->count('promotion_join_plan.id');
        $totalPage = ceil($count / $page_size);
        if ($totalPage == 0) {
            throw new \Exception(self::PROMOTION_HAS_NOT_PLANS, 404);
        }
        $page = ($page <= 1) ? 1 : $page;
        $plans = $base->orderBy('promotion_join_plan.id', 'desc')->offset(($page - 1) * $page_size)->limit($page_size)->get();
        return $this->json([
            'page_size'    => (int)$page_size,
            'count'        => (int)$count,
            'total_page'   => (int)$totalPage,
            'current_page' => (int)$page,
            'plans'        => $plans,
        ]);
    }

    /*----------------------------------------------------------------------*/

    /**
     * @param string $user_id
     * @return \App\Http\Utils\Response
     */
    public function userProfit($user_id)
    {
        return $this->json([
            'balance'     => (float)DB::table('promotion_join_plan')->where('user_id', $user_id)->sum('commission'),
            'withdrawals' => (float)DB::table('promotion_join_plan')->where('user_id', $user_id)->sum('withdrawals'),
        ]);
    }

    /*----------------------------------------------------------------------*/

    /**
     * @param Request $request
     * @param $user_id
     * @param $page
     * @return \App\Http\Utils\Response
     * @throws \Exception
     */
    public function userTeam(Request $request, $user_id, $page)
    {
        $start = $request->input('start', null);
        $end = $request->input('end', null);
        $base = DB::table('promotion_relation')
            ->select([
                'promotion_relation.user_id',
                'promotion_relation.shop_id',
                'promotion_relation.plan_id',
            ])->where([
                'promotion_relation.parent_user_id' => $user_id,
            ])->addSelect([
                'promotion_plan.name'
            ])->leftJoin('promotion_plan', function ($join) {
                $join->on('promotion_plan.id', '=', 'promotion_relation.plan_id');
            })->when($start, function ($query) use ($start) {
                $query->where('promotion_user_flow.create_time', '>=', $start);
            })->when($end, function ($query) use ($end) {
                $query->where('promotion_user_flow.create_time', '<=', $end);
            })->addSelect([
                'user_info.nickname', 'user_info.avatar'
            ])->leftJoin(sprintf('%suser_info as user_info', env('DB_DATABASE_USER', '')), function ($join) {
                $join->on('user_info.user_id', '=', 'promotion_relation.user_id');
            });
        $page_size = $request->input('page_size', $this->page_size);
        $count = $base->count('promotion_relation.id');
        $totalPage = ceil($count / $page_size);
        if ($totalPage == 0) {
            throw new \Exception(self::PROMOTION_HAS_NOT_TEAM, 404);
        }
        $page = ($page <= 1) ? 1 : $page;
        $team = $base->orderBy('promotion_relation.id', 'desc')
            ->offset(($page - 1) * $page_size)
            ->limit($page_size)
            ->get();
        return $this->json([
            'page_size'    => (int)$page_size,
            'count'        => (int)$count,
            'total_page'   => (int)$totalPage,
            'current_page' => (int)$page,
            'team'         => $team,
        ]);
    }

    /**
     * @param Request $request
     * @param $user_id
     * @param $page
     * @return \App\Http\Utils\Response
     * @throws \Exception
     */
    public function userWithdrawalsDetails(Request $request, $user_id, $page)
    {
        $start = $request->input('start', null);
        $end = $request->input('end', null);
        $base = DB::table('promotion_join_plan')
            ->select([
                'promotion_join_plan.user_id',
                'promotion_join_plan.shop_id',
                'promotion_join_plan.plan_id',
                'promotion_join_plan.commission',
                'promotion_join_plan.withdrawals',
            ])->where([
                'promotion_join_plan.user_id' => $user_id,
            ])->addSelect(['promotion_plan.name'])
            ->leftJoin('promotion_plan', function ($join) {
                $join->on('promotion_plan.id', '=', 'promotion_join_plan.plan_id');
            })->addSelect(DB::raw('shop_info.name as shop_name, shop_info.logo as shop_logo'))
            ->leftJoin(sprintf('%sshop_info as shop_info', env('DB_DATABASE_USER', '')), function ($join) {
                $join->on('shop_info.id', '=', 'promotion_join_plan.shop_id');
            })->when($start, function ($query) use ($start) {
                $query->where('promotion_user_flow.create_time', '>=', $start);
            })->when($end, function ($query) use ($end) {
                $query->where('promotion_user_flow.create_time', '<=', $end);
            });
        $page_size = $request->input('page_size', $this->page_size);
        $count = $base->count('promotion_join_plan.id');
        $totalPage = ceil($count / $page_size);
        if ($totalPage == 0) {
            throw new \Exception(self::PROMOTION_HAS_NOT_PLANS_DETAILS, 404);
        }
        $page = ($page <= 1) ? 1 : $page;
        $details = $base->orderBy('promotion_join_plan.id', 'desc')
            ->offset(($page - 1) * $page_size)
            ->limit($page_size)
            ->get();
        return $this->json([
            'page_size'    => (int)$page_size,
            'count'        => (int)$count,
            'total_page'   => (int)$totalPage,
            'current_page' => (int)$page,
            'details'      => $details,
        ]);
    }

    /**
     * @param Request $request
     * @param $user_id
     * @param $page
     * @return \App\Http\Utils\Response
     * @throws \Exception
     */
    public function userDetails(Request $request, $user_id, $page)
    {
        $start = $request->input('start', null);
        $end = $request->input('end', null);
        $base = DB::table('promotion_user_flow')
            ->select('promotion_user_flow.*')
            ->addSelect([
                'promotion_plan.name as plan_name'
            ])->leftJoin('promotion_plan', function ($join) {
                $join->on('promotion_plan.id', '=', 'promotion_user_flow.plan_id');
            })->addSelect(DB::raw('shop_info.name as shop_name, shop_info.logo as shop_logo'))
            ->leftJoin(sprintf('%sshop_info as shop_info', env('DB_DATABASE_USER', '')), function ($join) {
                $join->on('shop_info.id', '=', 'promotion_user_flow.shop_id');
            })->where('promotion_user_flow.user_id', $user_id)
            ->when($start, function ($query) use ($start) {
                $query->where('promotion_user_flow.create_time', '>=', $start);
            })->when($end, function ($query) use ($end) {
                $query->where('promotion_user_flow.create_time', '<=', $end);
            });
        $page_size = $request->input('page_size', $this->page_size);
        $count = $base->count('promotion_user_flow.id');
        $totalPage = ceil($count / $page_size);
        if ($totalPage == 0) {
            throw new \Exception(self::PROMOTION_HAS_NOT_PLANS_DETAILS, 404);
        }
        $page = ($page <= 1) ? 1 : $page;
        $details = $base->orderBy('promotion_user_flow.id', 'desc')
            ->offset(($page - 1) * $page_size)
            ->limit($page_size)
            ->get();
        return $this->json([
            'page_size'    => (int)$page_size,
            'count'        => (int)$count,
            'total_page'   => (int)$totalPage,
            'current_page' => (int)$page,
            'details'      => $details,
        ]);
    }

    /**
     * @param Request $request
     * @return \App\Http\Utils\Response
     * @throws \Exception
     */
    public function entrance(Request $request)
    {
        $this->validate($request, [
            'userId'  => 'required|alpha_num',
            'shopId'  => 'required|alpha_num',
            'orderNo' => 'required|string|min:1|max:255',
            'total'   => 'required|integer|min:0',
        ]);
        $orderId = DB::table('promotion_order')
            ->where([
                'order_num' => $request->input('orderNo'),
            ])->first(['id']);
        if (!is_null($orderId)) {
            throw new \Exception(self::PROMOTION_ORDER_ALREADY_FINISH, 202);
        }
        $order = new Order(
            $request->input('shopId'),
            $request->input('userId'),
            $request->input('orderNo'),
            $request->input('total')
        );
        return $this->json($order->account());
    }


}